/**
 * 
 */
package android.pim.vcard;

import java.io.ByteArrayOutputStream;

/**
 * <p>
 * Codec for the Quoted-Printable section of <a
 * href="http://www.ietf.org/rfc/rfc1521.txt">RFC 1521 </a>.
 * </p>
 * <p>
 * The Quoted-Printable encoding is intended to represent data that largely
 * consists of octets that correspond to printable characters in the ASCII
 * character set. It encodes the data in such a way that the resulting octets
 * are unlikely to be modified by mail transport. If the data being encoded are
 * mostly ASCII text, the encoded form of the data remains largely recognizable
 * by humans. A body which is entirely ASCII may also be encoded in
 * Quoted-Printable to ensure the integrity of the data should the message pass
 * through a character- translating, and/or line-wrapping gateway.
 * </p>
 * 
 * <p>
 * Note:
 * </p>
 * <p>
 * Rules #3, #4, and #5 of the quoted-printable spec are not implemented yet
 * because the complete quoted-printable spec does not lend itself well into the
 * byte[] oriented codec framework. Complete the codec once the steamable codec
 * framework is ready. The motivation behind providing the codec in a partial
 * form is that it can already come in handy for those applications that do not
 * require quoted-printable line formatting (rules #3, #4, #5), for instance Q
 * codec.
 * </p>
 * 
 * @see <a href="http://www.ietf.org/rfc/rfc1521.txt"> RFC 1521 MIME
 *      (Multipurpose Internet Mail Extensions) Part One: Mechanisms for
 *      Specifying and Describing the Format of Internet Message Bodies </a>
 * 
 * @author Apache Software Foundation
 * @since 1.3
 * @version $Id: QuotedPrintableCodec.java 798333 2009-07-27 23:41:58Z ggregory
 *          $
 */
public class QuotedPrintableCodec
{
	private static final byte ESCAPE_CHAR = '=';

	/**
	 * Decodes an array quoted-printable characters into an array of original
	 * bytes. Escaped characters are converted
	 * back to their original representation.
	 * 
	 * <p>
	 * This function implements a subset of quoted-printable encoding
	 * specification (rule #1 and rule #2) as defined in RFC 1521.
	 * </p>
	 * 
	 * @param bytes
	 *            array of quoted-printable characters
	 * @return array of original bytes
	 * @throws DecoderException
	 *             Thrown if quoted-printable decoding is unsuccessful
	 */
	public static final byte[] decodeQuotedPrintable(byte[] bytes)
			throws DecoderException
	{
		if (bytes == null)
		{
			return null;
		}

		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		for (int i = 0; i < bytes.length; i++)
		{
			int b = bytes[i];
			if (b == ESCAPE_CHAR)
			{
				try
				{
					int u = digit16(bytes[++i]);
					int l = digit16(bytes[++i]);
					buffer.write((char) ((u << 4) + l));
				} catch (ArrayIndexOutOfBoundsException e)
				{
					throw new DecoderException(
							"Invalid quoted-printable encoding", e);
				}
			} else
			{
				buffer.write(b);
			}
		}
		return buffer.toByteArray();
	}

	/**
	 * Returns the numeric value of the character <code>b</code> in radix 16.
	 * 
	 * @param b
	 *            The byte to be converted.
	 * @return The numeric value represented by the character in radix 16.
	 * 
	 * @throws DecoderException
	 *             Thrown when the byte is not valid per
	 *             {@link Character#digit(char,int)}
	 */
	static int digit16(byte b) throws DecoderException
	{
		int i = Character.digit((char) b, 16);
		if (i == -1)
		{
			throw new DecoderException(
					"Invalid URL encoding: not a valid digit: " + b);
		}
		return i;
	}
}
